package com.mjlf.framework.aop;

import com.mjlf.framework.annotation.aop.After;
import com.mjlf.framework.annotation.aop.Before;
import com.mjlf.framework.annotation.mydata.Mapper;
import com.mjlf.framework.annotation.mydata.Sql;
import com.mjlf.framework.mydata.MapperProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @auther a123
 * @create 2018-08-29 18:57
 * @desc 正确方法管理，
 */
public final class ProxyManager {

    public static <T> T createProxy(final Class<T> targetClass) {
        return (T) Enhancer.create(targetClass, new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object result;
                if (AdviseUtil.needProxy(method)) {//判断是否需要做方法代理
                    List<AdviseMethod> proxyMethods = new ArrayList<>();
                    AdviseMethodManager.PROXY_METHOD.keySet().stream()
                            .filter(annotation -> AdviseUtil.parseMethodProxy(annotation, method))
                            .forEach(annotation -> {
                                proxyMethods.add(AdviseMethodManager.PROXY_METHOD.get(annotation));
                            });
                    proxyMethods.stream().filter(proxyMethod -> {
                        if (proxyMethod.getMethod().isAnnotationPresent(Before.class)) {
                            return true;
                        }
                        return false;
                    }).forEach(proxyMethod -> {
                        try {
                            //处理方法参数
                            List<Object> adviceParams = setParams(proxyMethod, method, objects);
                            Object[] adviceParam = adviceParams == null ? null : adviceParams.toArray();
                            proxyMethod.getMethod().invoke(proxyMethod.getObject(), adviceParam);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new RuntimeException("参数存在问题");
                        }
                    });

                    if (method.isAnnotationPresent(Sql.class)) {
                        result = MapperProxy.createMapperProxy(method, objects, methodProxy, o);
                    } else {
                        result = methodProxy.invokeSuper(o, objects);
                    }

                    proxyMethods.stream().filter(proxyMethod -> {
                        if (proxyMethod.getMethod().isAnnotationPresent(After.class)) {
                            return true;
                        }
                        return false;
                    }).forEach(proxyMethod -> {
                        try {
                            List<Object> adviceParams = setParams(proxyMethod, method, objects);
                            if (proxyMethod.getReturnType() != After.class) {
                                if (adviceParams == null) {
                                    adviceParams = new ArrayList<>();
                                }
                                adviceParams.add(result);
                            }
                            Object[] adviceParam = adviceParams == null ? null : adviceParams.toArray();
                            proxyMethod.getMethod().invoke(proxyMethod.getObject(), adviceParam);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                } else if (targetClass.isAnnotationPresent(Mapper.class)) {
                    result = MapperProxy.createMapperProxy(method, objects, methodProxy, o);
                }
                else {
                    result = methodProxy.invokeSuper(o, objects);
                }
                return result;
            }
        });
    }

    public static List<Object> setParams(AdviseMethod proxyMethod, Method method, Object[] args) throws Exception {
        Class<?>[] adviseArgsTypes = proxyMethod.getArgsType();

        List<Object> adviceParams = null;
        if (adviseArgsTypes.length != 0) {
            adviceParams = new ArrayList<>();
            for (int i = 0; i < adviseArgsTypes.length; i++) {
                Class<?> adviceArgsType = adviseArgsTypes[i];
                if (adviceArgsType == Method.class) {
                    adviceParams.add(method);
                } else {
                    if (args == null) {
                        throw new Exception("参数存在错误");
                    } else {
                        for (Object object : args) {
                            adviceParams.add(object);
                        }
                    }
                }
            }
        }
        return adviceParams;
    }
}
